#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <cutils/uevent.h>
#include <mincrypt/sha.h>

#include "bootloader.h"
#include "common.h"
#include "cutils/properties.h"
#include "cutils/android_reboot.h"
#include "install.h"
#include "minui/minui.h"
#include "minzip/DirUtil.h"
#include "roots.h"
#include "efuse.h"
#include "usb_burning.h"
#include "device.h"
#include "cmd_excute.h"
#include <sys/mount.h>
#include <sys/wait.h>

extern "C" {
#include "fw_env.h"
}

/* 
  *  partition_burn_type value:
  *  0 : use cache partition
  *  1 : use preloaded partition
  *  2 : use media partition
  */
extern char G_backup_path[100];
void finish_recovery(const char *send_intent);
int partition_burn_type;

static const char *MEDIA_ROOT = "/media";

static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";

static const char *USB_LOG_FILE=NULL;
static const char *USB_KMESG_FILE=NULL;
#if 0
static const char *USB_LOG_FILE = "/media/recovery.log";
static const char *USB_KMESG_FILE = "/media/kmsg.log";
#endif

#define USB_MS_DEV_CTRLER 	"/sys/devices/lm0/gadget/gadget-lun0/file"

#define USB_MSG_GET_PATH	"/sys/class/usb_recovery/usb_recovery0/file_complete"
#define USB_MSG_BUF_SIZE	64*1024

#define USB_MSG_SET_PATH	"/sys/class/usb_recovery/usb_recovery0/update_complete"
#define USB_MSG_SUCCESS      	'1'

#define USB_BURNING_UEVENT	     "change@/devices/virtual/usb_recovery/usb_recovery0"

#define USB_MSG_CMD_UPDATE           "update"
#define USB_MSG_CMD_WIPE_DATA        "wipe_data"
#define USB_MSG_CMD_WIPE_CACHE       "wipe_cache"
#define USB_MSG_CMD_WIPE_MEDIA       "wipe_media"
#define USB_MSG_CMD_RESET            "reset"
#define USB_MSG_CMD_SHUTDOWN         "shutdown"
#define USB_MSG_CMD_ERASE_TEST       "erase_test"
#define USB_MSG_CMD_GET_LOG          "get_log"
#define USB_MSG_CMD_RUN_COMMOND_RECOVERY     "run_command"

//usb burn key command
#define USB_MSG_CMD_EFUSE_READ_VERSION          "efuse read version"
#define USB_MSG_CMD_EFUSE_WRITE_VERSION         "efuse write version"
#define USB_MSG_CMD_EFUSE_READ_MAC              "efuse read mac"
#define USB_MSG_CMD_EFUSE_WRITE_MAC             "efuse write mac "
#define USB_MSG_CMD_EFUSE_READ_BT_MAC           "efuse read bt_mac"
#define USB_MSG_CMD_EFUSE_WRITE_BT_MAC          "efuse write bt_mac "
#define USB_MSG_CMD_EFUSE_READ_WIFI_MAC         "efuse read wifi_mac"	
#define USB_MSG_CMD_EFUSE_WRITE_WIFI_MAC        "efuse write wifi_mac "
#define USB_MSG_CMD_EFUSE_READ_USID             "efuse read usid"
#define USB_MSG_CMD_EFUSE_WRITE_USID            "efuse write usid "	
#define USB_MSG_CMD_EFUSE_READ_HDCP             "read hdcp"
#define USB_MSG_CMD_EFUSE_WRITE_HDCP            "write hdcp:"

//efuse version
#define EFUSE_VERSION_MESON3       	 	"01:02:03"
#define EFUSE_VERSION_MESON6        		"02"

//flash key node
#define PATH_VERSION                         	"/sys/class/aml_keys/aml_keys/version"
#define PATH_KEY_READ                      	"/sys/class/aml_keys/aml_keys/key_read"
#define PATH_KEY_WRITE                    	"/sys/class/aml_keys/aml_keys/key_write"

#define USB_MSG_RET_SUCCESS         		"success"
#define USB_MSG_RET_FAILED	           	"failed"
#define USB_MSG_RET_READY             		"ready"
#define USB_MSG_RET_BUSY               		"busy"


int get_usb_msg(char *msg) {
    size_t read = 0;
    FILE* fin = fopen(USB_MSG_GET_PATH, "rb");
    if (fin == NULL) {
        LOGE("Failed to open %s (%s)\n", USB_MSG_GET_PATH, strerror(errno));
        return NULL;
    }

    if ((read = fread(msg, 1, USB_MSG_BUF_SIZE, fin)) > 0) {
        printf("get_usb_msg: read=%d\n", read);
    }

    if (fclose(fin) != 0) {
        LOGE("Failed to close %s (%s)\n", USB_MSG_GET_PATH, strerror(errno));
        return NULL;
    }

    return read;
}

int set_usb_msg(char *msg, size_t size) {
    FILE* fout = fopen(USB_MSG_SET_PATH, "wb");
    if (fout == NULL) {
        LOGE("Failed to open %s (%s)\n", USB_MSG_SET_PATH, strerror(errno));
        return NULL;
    }

    if (fwrite(msg, 1, size, fout) != size) {
        LOGE("Short write of %s (%s)\n", USB_MSG_SET_PATH, strerror(errno));
        return NULL;
    }

    if (fclose(fout) != 0) {
        LOGE("Failed to close %s (%s)\n", USB_MSG_SET_PATH, strerror(errno));
        return NULL;
    }

    return size;
}

int usb_burning_main_test(int status) {
    int time_out = 0;
    size_t usb_msg_size = 0;
    char usb_msg[USB_MSG_BUF_SIZE];
    //usb_msg[0] = USB_MSG_SUCCESS;

    int result = 0;
    pid_t pid = 0;

    while(ensure_path_mounted("/media")) {
        printf("ensure_path_mounted. time out = %d\n", time_out++);
        if(time_out > 3) {
            break;
        }
        sleep(1);
    }
	
    sleep(1);
	
    pid = fork();
    if (pid == 0) {
        result = execv("/sbin/open_mass_storage.sh", NULL);
        if (result)
            LOGE("open_mass_storage failed(%s)!\n", strerror(errno));
        _exit(-1);
    }
    waitpid(pid, &result, 0);
    if (WIFEXITED(result)) {
        if (WEXITSTATUS(result) != 0) {
            LOGE("open_mass_storage failed(%d)!\n", WEXITSTATUS(result));
            result = -1;
        }
        else
            result = 0;
    }
    else if (WIFSIGNALED(result)) {
        LOGE("open_mass_storage: open_mass_storage terminated on (%d)\n", WTERMSIG(result));
        result = -1;
    }
    else
        result = 0;

    sleep(2);

    time_out = 0;
    memset(usb_msg, 0, USB_MSG_BUF_SIZE);
    if((status == INSTALL_SUCCESS)) {
        usb_msg_size = strlen("success");
        strncpy(usb_msg, "success", usb_msg_size);
    }
    else {
        usb_msg_size = strlen("failed:update");
        strncpy(usb_msg, "failed:update", usb_msg_size);
    }

    //LOGE("usb_msg(%d):%s\n", usb_msg_size, usb_msg);
	
    while(!(set_usb_msg(usb_msg, usb_msg_size)==usb_msg_size)) {
        printf("wait USB_MSG_SUCCESS. time out = %d\n", time_out++);
        if(time_out > 10) {
            break;
        }
        sleep(1);
    }

    memset(usb_msg, 0, USB_MSG_BUF_SIZE);
    while(1) {
        usb_msg_size = get_usb_msg(usb_msg);
        if(usb_msg_size > 0) {
            printf("usb_msg=%s\n", usb_msg);
            if((strncmp(usb_msg, "RESET", 5) == 0) || (strncmp(usb_msg, "reset", 5) == 0)) {
                sync();
                android_reboot(ANDROID_RB_RESTART2, 0, "normal_reboot");
            }
            else if((strncmp(usb_msg, "SHUTDOWN", 8) == 0) || (strncmp(usb_msg, "shutdown", 8) == 0)) {
                sync();
                android_reboot(ANDROID_RB_RESTART2, 0, "charging_reboot");
            }
            else if(strncmp(usb_msg, "erase_test", 10) == 0) {
                char* env_name = "preboot";
                char* env_val = "nand rom_protect off; nand scrub 0; reset";
                //char* env_val = "printenv";
                char *fw_argv[] = { "fw_setenv",
                    env_name,
                    env_val,
                    NULL };
                if(fw_setenv(3, fw_argv) != 0) {
                    usb_msg_size = strlen("failed(erase_test):set env failed");
                    strncpy(usb_msg, "failed(erase_test):set env failed", usb_msg_size);
                    while(!(set_usb_msg(usb_msg, usb_msg_size)==usb_msg_size)) {
                        printf("wait USB_MSG_SUCCESS. time out = %d\n", time_out++);
                        if(time_out > 10) {
                            break;
                        }
                        sleep(1);
                    }
                }
                sync();
                android_reboot(ANDROID_RB_RESTART2, 0, "charging_reboot");
            }
        }
        printf("wait\n");
        sleep(1);
    }
	
    //android_reboot(ANDROID_RB_RESTART2, 0, "usb_burner_reboot");
    sync();
}

inline void usb_func_reset(void) {
    sync();
    android_reboot(ANDROID_RB_RESTART2, 0, "normal_reboot");
    exit(0);
}

inline void usb_func_shutdown(void) {
    sync();
    sleep(2);
    android_reboot(ANDROID_RB_RESTART2, 0, "charging_reboot");
    exit(0);
}

inline int usb_func_wipe_data(void) {
    int status = INSTALL_SUCCESS;
    
    LOGI("usb_func_wipe_data\n");
    if (erase_volume("/data")) status = INSTALL_ERROR;
    if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    
    return status;
}

inline int usb_func_wipe_cache(void) {
    int status = INSTALL_SUCCESS;
    
    LOGI("usb_func_wipe_cache\n");
    if (erase_volume("/cache")) status = INSTALL_ERROR;
    if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    
    return status;
}

inline int usb_func_format_cache(const char *fstype) {
    if (!strcmp(fstype, "ext4") ) {
        Volume* v = volume_for_path("/cache");
        printf("mount_point=%s, fs_type=%s, device=%s\n",v->mount_point, v->fs_type, v->device);
        v->fs_type = "ext4";        //set cache partition fstype to "ext4"
        printf("mount_point=%s, fs_type=%s, device=%s\n",v->mount_point, v->fs_type, v->device);
        if (!format_volume("/cache")) {
            printf("format cache(fstype:ext4) success\n");
            return 0;
        }
        else {
            printf("format cache(fstype:ext4) failed\n");
            return -1;
        }
    }
    else {
        printf("format cache: fs_type \"%s\" unsupported\n", fstype);
        return -1;
    }
}

inline int usb_func_wipe_preloaded(void) {
    int status = INSTALL_SUCCESS;
    
    LOGI("usb_func_wipe_preloaded\n");
    if (erase_volume("/preloaded")) status = INSTALL_ERROR;
    if (status != INSTALL_SUCCESS) ui->Print("Preloaded wipe failed.\n");
    
    return status;
}

inline int usb_func_wipe_media(void) {
    int status = INSTALL_SUCCESS;
    
    LOGI("usb_func_wipe_media\n");
    if (erase_volume(MEDIA_ROOT)) status = INSTALL_ERROR;
    if (status != INSTALL_SUCCESS) ui->Print("Media wipe failed.\n");
    
    return status;
}

inline int usb_func_recovery_data(char const *cmd) {
    int status = INSTALL_SUCCESS;
    char *tmp = NULL;
    
    //LOGI("usb_func_recovery_data\n");
    LOGI("usb_func_recovery_data:%s\n", cmd);
    ensure_path_mounted("/system");
    ensure_path_mounted("/data");
    ensure_path_mounted("/cache");
    sleep(1);
    tmp = (char *)(cmd + strlen(USB_MSG_CMD_RUN_COMMOND_RECOVERY) + 1);
    
    return recovery_run_cmd(tmp);
}

inline int usb_func_backup_log(void) {
    copy_log_file(TEMPORARY_LOG_FILE, USB_LOG_FILE, false);
    //copy_log_file("/proc/kmsg", USB_KMESG_FILE, false);
    sync();
    return INSTALL_SUCCESS;
}

inline int usb_func_rm_log(void) {
    unlink(USB_LOG_FILE);
    sync();
    return INSTALL_SUCCESS;
}

int usb_cmd_process(char *cmd, ssize_t length) {
    int status = INSTALL_SUCCESS;
    int wipe_cache = 0;
    char file_path[USB_MSG_BUF_SIZE], str_msg[USB_MSG_BUF_SIZE];
    int i, ret = -1, hdcp_key_len = 288, writeHdcp_flag =1;
    char key_data[512], hdcp_verify_data_receive[20], hdcp_verify_data_calculate[20];

    LOGE("usb_cmd_process:%s\n", cmd);

#if defined(WRITE_TO_EFUSE_ENABLE)
    printf("burn key to efuse...\n");
    Device* device = make_device();
    RecoveryUI * ui = device->GetUI();
#elif defined(WRITE_TO_FLASH_ENABLE)
    printf("burn key to flash...\n");
#endif

    memset(key_data, 0, sizeof(key_data));
    memset(hdcp_verify_data_receive, 0, sizeof(hdcp_verify_data_receive));
    memset(hdcp_verify_data_calculate, 0, sizeof(hdcp_verify_data_calculate));

    if(strncmp(cmd, USB_MSG_CMD_UPDATE, strlen(USB_MSG_CMD_UPDATE)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        memset(file_path, 0, USB_MSG_BUF_SIZE);
        memset(str_msg, 0, USB_MSG_BUF_SIZE);	
        if(!partition_burn_type)
            sprintf(file_path, "/cache/%s", (cmd+strlen(USB_MSG_CMD_UPDATE)+1));
        else if(partition_burn_type == 1)
            sprintf(file_path, "/preloaded/%s", (cmd+strlen(USB_MSG_CMD_UPDATE)+1));
        else if(partition_burn_type == 2)
            sprintf(file_path, "/media/%s", (cmd+strlen(USB_MSG_CMD_UPDATE)+1));

        status = install_package(file_path, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if(status == INSTALL_SUCCESS) {
	     memset(G_backup_path,0,sizeof(G_backup_path));
	     strcpy(G_backup_path,file_path);
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
	     finish_recovery(NULL);
	     ui->SetBackground(RecoveryUI::INSTALL_SUCCESS);
	     ui->SetProgressType(RecoveryUI::EMPTY);
	     sleep(5);
            unlink(file_path);
            sync();
        }
        else {
            sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
            usb_func_backup_log();
        }
    }
    else if(strncmp(cmd, USB_MSG_CMD_WIPE_DATA, strlen(USB_MSG_CMD_WIPE_DATA)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        status = usb_func_wipe_data();
        if(status == INSTALL_SUCCESS) {
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
        }
        else {
            status = usb_func_wipe_data();
            if(status == INSTALL_SUCCESS) {
                sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
            }
            else{
                sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
                usb_func_backup_log();
            }
        }
    }
    else if(strncmp(cmd, USB_MSG_CMD_WIPE_CACHE, strlen(USB_MSG_CMD_WIPE_CACHE)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));

        /* Not erase cache partition actually when using cache partition to burn */
        if(partition_burn_type == 0) {
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
        }
        else {
            status = usb_func_wipe_cache();
            if(status == INSTALL_SUCCESS) {
                sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
            }
            else {
                status = usb_func_wipe_cache();
                if(status == INSTALL_SUCCESS) {
                    sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
                }
                else {
                    sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
                    usb_func_backup_log();
                }
            }
        }
    }
    else if(strncmp(cmd, USB_MSG_CMD_WIPE_MEDIA, strlen(USB_MSG_CMD_WIPE_MEDIA)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));

        /* Not erase media partition actually when using media partition to burn */
        if(partition_burn_type == 2) {
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
        }
        else {
            status = usb_func_wipe_media();
            if(status == INSTALL_SUCCESS) {
                sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
            }
            else {
                sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
                usb_func_backup_log();
            }
        }
    }
    else if(strncmp(cmd, USB_MSG_CMD_RESET, strlen(USB_MSG_CMD_RESET)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        usb_func_reset();
    }
    else if(strncmp(cmd, USB_MSG_CMD_SHUTDOWN, strlen(USB_MSG_CMD_SHUTDOWN)) == 0) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
        /* wipe cache later, it needs to set cache partition fstype to "ext4" before shutdown. */
        if(!partition_burn_type) {
            /*stop massstorage to pc*/
            FILE *fp = NULL;
            const char *null_device = " ";
            fp = fopen(USB_MS_DEV_CTRLER, "w");
            if(fp == NULL) {
                printf("no %s found\n", USB_MS_DEV_CTRLER);
                return -1;
            }else {
                int result = fwrite(null_device, 1, strlen(null_device), fp); 
                if(result == strlen(null_device)) {
                    printf("echo   > %s successful\n", USB_MS_DEV_CTRLER);
                }else {
                    printf("echo   > %s failed\n", USB_MS_DEV_CTRLER);
                    fclose(fp);
                    return -1;
                }
                fclose(fp); 
            }
           
            Volume* v = volume_for_path("/cache");
            if(v!=NULL){
                printf("mount_point=%s, fs_type=%s, device=%s\n",v->mount_point, v->fs_type, v->device);
                ensure_path_unmounted(v->mount_point);
                sync();
            }else {
                printf("usb_func volume_for_path(/cache) returned NULL\n");
                return -1;
            }
            status = usb_func_format_cache("ext4");
            if(!status) {
                sync();
                printf("usb_func_format_cache(ext4) success\n");
                int fd_cache = open(v->device, O_RDWR);
                fsync(fd_cache);
                close(fd_cache);
            }
            else {
                printf("usb_func_format_cache(\"ext4\") failed\n");
                return -1;
            }
        }

        usb_func_shutdown();
    }
    else if(strncmp(cmd, USB_MSG_CMD_RUN_COMMOND_RECOVERY, strlen(USB_MSG_CMD_RUN_COMMOND_RECOVERY)) == 0) {
        LOGI("usb_func_recovery_data_enter\n");
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        status = usb_func_recovery_data(cmd);
        if(status == INSTALL_SUCCESS) {
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
        }
        else {
            sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
            usb_func_backup_log();
        }
    }
    else if(strncmp(cmd, USB_MSG_CMD_ERASE_TEST, strlen(USB_MSG_CMD_ERASE_TEST)) == 0) {
        char* env_name = "preboot";
        char* env_val = "nand rom_protect off; nand scrub 0; reset";
        char *fw_argv[] = { "fw_setenv",
            env_name,
            env_val,
            NULL };
        if(fw_setenv(3, fw_argv) == 0) {
            sprintf(str_msg, "%s(%s):ok", USB_MSG_RET_SUCCESS, cmd);
            sync();
            android_reboot(ANDROID_RB_RESTART2, 0, "charging_reboot");
            exit(0);
        }
        else {
            sprintf(str_msg, "%s(%s):bad", USB_MSG_RET_FAILED, cmd);
            usb_func_backup_log();
        }
    }
    //command: "efuse read version"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_VERSION, strlen(USB_MSG_CMD_EFUSE_READ_VERSION))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_read_version(key_data, ui);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(version has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(efuse read version failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        sprintf(str_msg, "%s", "failed:(flash not be initialized)");
#endif
    }
    //command: "efuse write version"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_VERSION, strlen(USB_MSG_CMD_EFUSE_WRITE_VERSION))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        char *version = NULL;
#if defined(MESON3)
        version = EFUSE_VERSION_MESON3;
#elif defined(MESON6)
        version = EFUSE_VERSION_MESON6;
#endif
        ret = efuse_write_version(version, ui);
        if(!ret)
            sprintf(str_msg, "success:(%s)", version);
        else
            sprintf(str_msg, "%s", "failed:(efuse write version failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_write_version(PATH_VERSION, key_data);
        if(ret == 0) {
            sprintf(str_msg, "%s", "success:(init flash success)");
            printf("init flash success\n");
        }
        else if(ret == 1) {
            sprintf(str_msg, "%s", "success:(flash already inited)");
            printf("flash already inited\n");
        }
        else {
            sprintf(str_msg, "%s", "failed:(init flash failed)");
            printf("init flash failed\n");
            return -1;
        }
#endif
    }	
    //command: "efuse read mac"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_MAC, strlen(USB_MSG_CMD_EFUSE_READ_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)		
        ret = efuse_read_mac(key_data, EFUSE_MAC, ui);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);	
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac has been not writen)");
        else		
            sprintf(str_msg, "%s", "failed:(efuse read mac failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_read_mac(PATH_KEY_READ, key_data);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(flash read mac failed)");
#endif		
    }	
    //command: "efuse write mac xx:xx:xx:xx:xx:xx"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_MAC, strlen(USB_MSG_CMD_EFUSE_WRITE_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        char *mac_key = cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_MAC);
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_write_mac(mac_key, EFUSE_MAC, ui);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_key);
        else
            sprintf(str_msg, "%s", "failed:(efuse write mac failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_write_mac(PATH_KEY_WRITE, mac_key);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_key);
        else
            sprintf(str_msg, "%s", "failed:(flash write mac failed)");
#endif		
    }
    //command: "efuse read bt_mac"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_BT_MAC, strlen(USB_MSG_CMD_EFUSE_READ_BT_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)		
        ret = efuse_read_mac_bt(key_data, EFUSE_MAC_BT, ui);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);		
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac_bt has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(efuse read mac_bt failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_read_mac_bt(PATH_KEY_READ, key_data);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac_bt has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(flash read mac_bt failed)");
#endif			
    }
    //command: "efuse write bt_mac xx:xx:xx:xx:xx:xx"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_BT_MAC, strlen(USB_MSG_CMD_EFUSE_WRITE_BT_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        char *mac_bt_key = cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_BT_MAC);
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_write_mac_bt(mac_bt_key, EFUSE_MAC_BT, ui);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_bt_key);
        else
            sprintf(str_msg, "%s", "failed:(efuse write mac_bt failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_write_mac_bt(PATH_KEY_WRITE, mac_bt_key);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_bt_key);
        else
            sprintf(str_msg, "%s", "failed:(flash write mac_bt failed)");
#endif
	}
    //command: "efuse read wifi_mac"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_WIFI_MAC, strlen(USB_MSG_CMD_EFUSE_READ_WIFI_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_read_mac_wifi(key_data, EFUSE_MAC_WIFI, ui);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac_wifi has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(efuse read mac_wifi failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_read_mac_wifi(PATH_KEY_READ, key_data);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(mac_wifi has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(flash read mac_wifi failed)");
#endif			
	}
    //command: "efuse write wifi_mac xx:xx:xx:xx:xx:xx"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_WIFI_MAC, strlen(USB_MSG_CMD_EFUSE_WRITE_WIFI_MAC))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        char *mac_wifi_key = cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_WIFI_MAC);
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_write_mac_wifi(mac_wifi_key, EFUSE_MAC_WIFI, ui);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_wifi_key);
        else
            sprintf(str_msg, "%s", "failed:(efuse write mac_wifi failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_write_mac_wifi(PATH_KEY_WRITE, mac_wifi_key);
        if(!ret)
            sprintf(str_msg, "success:(%s)", mac_wifi_key);
        else
            sprintf(str_msg, "%s", "failed:(flash write mac_wifi failed)");
#endif
    }	
    //command: "efuse read usid"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_USID, strlen(USB_MSG_CMD_EFUSE_READ_USID))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)		
        ret = efuse_read_usid(key_data, EFUSE_USID, ui);
        if(ret==0)	
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)				
            sprintf(str_msg, "%s", "failed:(usid has been not writen)");	
        else
            sprintf(str_msg, "%s", "failed:(efuse read usid failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_read_usid(PATH_KEY_READ, key_data);
        if(ret==0)
            sprintf(str_msg, "success:(%s)", key_data);
        else if(ret==1)				
            sprintf(str_msg, "%s", "failed:(usid has been not writen)");		
        else
            sprintf(str_msg, "%s", "failed:(flash read usid failed)");		
#endif			
    }
    //command: "efuse write usid xxxxx..."
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_USID, strlen(USB_MSG_CMD_EFUSE_WRITE_USID))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        char *usid_key = cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_USID);
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_write_usid(usid_key, EFUSE_USID, ui);
        if(!ret)
            sprintf(str_msg, "success:(%s)", usid_key);
        else
            sprintf(str_msg, "%s", "failed:(efuse write usid failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_write_usid(PATH_KEY_WRITE, usid_key);
        if(!ret)
            sprintf(str_msg, "success:(%s)", usid_key);
        else		
            sprintf(str_msg, "%s", "failed:(flash write usid failed)");		
#endif
    }	
    //command: "read hdcp"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_READ_HDCP, strlen(USB_MSG_CMD_EFUSE_READ_HDCP))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
#if defined(WRITE_TO_EFUSE_ENABLE)
        ret = efuse_read_hdcp(key_data, EFUSE_HDCP, ui);
        if(ret==0)
            sprintf(str_msg, "%s", "success:(hdcp has been writen)");	
        else if(ret==1)
            sprintf(str_msg, "%s", "failed:(hdcp has been not writen)");		
        else
            sprintf(str_msg, "%s", "failed:(efuse read hdcp failed)");
#elif defined(WRITE_TO_FLASH_ENABLE)
        ret = flash_read_hdcp(PATH_KEY_READ, key_data);
        if(ret==0)
            sprintf(str_msg, "%s", "success:(hdcp has been writen)");
        else if(ret==1)	
            sprintf(str_msg, "%s", "failed:(hdcp has been not writen)");
        else
            sprintf(str_msg, "%s", "failed:(flash read hdcp failed)");
#endif			
    }
    //command: "write hdcp:"
    else if(!strncmp(cmd, USB_MSG_CMD_EFUSE_WRITE_HDCP, strlen(USB_MSG_CMD_EFUSE_WRITE_HDCP))) {
        set_usb_msg(USB_MSG_RET_BUSY, strlen(USB_MSG_RET_BUSY));
        
        //copy 288 hdcp key datas and 20 hdcp verify datas
        memcpy(key_data, cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_HDCP), hdcp_key_len);
        memcpy(hdcp_verify_data_receive, cmd+strlen(USB_MSG_CMD_EFUSE_WRITE_HDCP)+hdcp_key_len, 20);
        printf("receive %d hdcp key datas:\n", hdcp_key_len);
        for(i=0; i<hdcp_key_len; i++)
            printf("%.2x:", key_data[i]);

        printf("\nreceive 20 hdcp key verify datas:\n");
        for(i=0; i<20; i++)
            printf("%.2x:", hdcp_verify_data_receive[i]);
        printf("\n");

        //verify enable
        printf("start to verify %d hdcp key datas...\n", hdcp_key_len);
        SHA(key_data, hdcp_key_len, (uint8_t*)hdcp_verify_data_calculate);
        printf("verify & get 20 hdcp verify datas:\n");
        for(i=0; i<20; i++)
            printf("%.2x:", hdcp_verify_data_calculate[i]);
        printf("\n");

        ret = memcmp(hdcp_verify_data_receive, hdcp_verify_data_calculate, 20);
        if(ret != 0)
            writeHdcp_flag = 0;

#if defined(WRITE_TO_EFUSE_ENABLE)
        if(writeHdcp_flag) {        //verify success,hdcp can write
            ret = efuse_write_hdcp(key_data, EFUSE_HDCP, ui);
            if(!ret)
                sprintf(str_msg, "%s", "success:(efuse write hdcp success)");
            else
                sprintf(str_msg, "%s", "failed:(efuse write hdcp failed)");
        }
        else {
            sprintf(str_msg, "%s", "failed:(hdcp data verify not mach)");
            printf("%s\n",str_msg);
            return -1;
        }
#elif defined(WRITE_TO_FLASH_ENABLE)
        if(writeHdcp_flag) {
            ret = flash_write_hdcp(PATH_KEY_WRITE, key_data);
            if(!ret)
                sprintf(str_msg, "%s", "success:(flash write hdcp success)");
            else
                sprintf(str_msg, "%s", "failed:(flash write hdcp failed)");
        }	
        else {
            sprintf(str_msg, "%s", "failed:(hdcp data verify not mach)");
            printf("%s\n",str_msg);
            return -1;
        }
#endif	
    }
    else {
        sprintf(str_msg, "%s(%s):unknow cmd", USB_MSG_RET_FAILED, cmd);
        usb_func_backup_log();
    }

    set_usb_msg(str_msg, strlen(str_msg));
    printf("%s\n",str_msg);
    
    return 0;
}

int usb_burning_main(int opt) {
    int usb_evt_socket, time_out = 0, result = 0;
    ssize_t in = 0;
    char usb_evt_msg[USB_MSG_BUF_SIZE];
    pid_t pid = 0;

    char *mountPoint = NULL;
    char *fsType = NULL;
    char *device = NULL;

    partition_burn_type = 0;
    if((access("/dev/block/preloaded", F_OK) == 0))
        partition_burn_type = 1;
    else if((access("/dev/block/media", F_OK) == 0))
        partition_burn_type = 2;

    if(!partition_burn_type) {
        USB_LOG_FILE     = "/cache/recovery.log";
        USB_KMESG_FILE = "/cache/kmsg.log";
        printf("Using cache partition to burn...\n");
    }
    else if(partition_burn_type == 1) {
        USB_LOG_FILE     = "/preloaded/recovery.log";
        USB_KMESG_FILE = "/preloaded/kmsg.log";
        printf("Using preloaded partition to burn...\n");
    }
    else if(partition_burn_type == 2) {
        USB_LOG_FILE     = "/media/recovery.log";
        USB_KMESG_FILE = "/media/kmsg.log";
        printf("Using media partition to burn...\n");
    }

    //use cache partition
    if(!partition_burn_type) {
        Volume* v = volume_for_path("/cache");
        printf("mount_point=%s, fs_type=%s, device=%s\n",v->mount_point, v->fs_type, v->device);	
        v->fs_type = "vfat";                //set cache partition fstype to "vfat"
        mountPoint  = (char *)v->mount_point;
        fsType        = (char *)v->fs_type;
        device = (char *)v->device;
    }
    //use preloaded partition
    else if(partition_burn_type == 1) {
        mountPoint  = "/preloaded";
        fsType        = "vfat";
        device = "/dev/block/preloaded";
    }
    //use media partition
    else if(partition_burn_type == 2) {
        mountPoint  = "/media";
        fsType        = "vfat";
        device = "/dev/block/media";
    }
    printf("mount_point=%s, fs_type=%s, device=%s\n", mountPoint, fsType, device);

    result = ensure_path_unmounted(mountPoint);
    printf("ensure_path_unmounted(%s)=%d\n", mountPoint, result);

    //mkfs.vfat /dev/block/cache(preloaded/media)
    if(partition_burn_type == 2) {  //media partition:with a volume label name to format
        char value[PROPERTY_VALUE_MAX+1];
        property_get("ro.media.partition.label", value, RECOVERY_MEDIA_LABEL);
        char *argv1[] = { "/sbin/busybox", "mkfs.vfat", "-n", value, device, NULL};
        printf("valume name:value=%s\n", value);
        result = CmdRuner::run_command("/sbin/busybox", argv1);
        if(!result)
            printf("mkfs.vfat %s successful\n", device);
        else {
            printf("mkfs.vfat %s failed\n", device);
            return -1;
        }
    }
    else {
        char *argv2[] = { "/sbin/busybox", "mkfs.vfat", device, NULL};
        result = CmdRuner::run_command("/sbin/busybox", argv2);
        if(!result)
            printf("mkfs.vfat %s successful\n", device);
        else {
            printf("mkfs.vfat %s failed\n", device);
            return -1;
        }
    }
    usleep(2000);
    
    //mkdir /cache(preloaded/media)
    mkdir(mountPoint, 0755);
    printf("mkdir %s successful\n", mountPoint);

    //mount -t vfat  /dev/block/cache(preloaded/media)  /cache(preloaded/media)
    if(mount(device, mountPoint, "vfat", MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
        printf("cann't mount %s to %s\n", device, mountPoint);
        return -1;
    }
    printf("mount %s to %s successful\n", device, mountPoint);
    usleep(2000);

    //echo /dev/block/cache(preloaded/media) > /sys/devices/lm0/gadget/gadget-lun0/file
    FILE *fp = NULL;
    fp = fopen(USB_MS_DEV_CTRLER, "w");
    if(fp == NULL) {
        printf("no %s found\n", USB_MS_DEV_CTRLER);
        return -1;
    }
    else {
        result = fwrite(device, 1, strlen(device), fp);
        if(result == strlen(device))
            printf("echo %s > %s successful\n", device, USB_MS_DEV_CTRLER);
        else {
            printf("echo %s > %s failed\n", device, USB_MS_DEV_CTRLER);
            return -1;
        }
        fclose(fp);
        fp = NULL;
    }

#if 0
    //use media partition
    if(!opt) {  //opt=1,do not wipe media
        while(usb_func_wipe_media()) {
            printf("usb_func_wipe_media. time out = %d\n", time_out++);
            if(time_out > 3) {
                break;
            }
            sleep(1);
        }
        sleep(1);
        time_out = 0;
    }
	
    while(ensure_path_mounted("/media")) {
        printf("ensure_path_mounted. time out = %d\n", time_out++);
        if(time_out > 3) {
            break;
        }
        sleep(1);
    }
    sleep(1);
	
    pid = fork();
    if (pid == 0) {
        result = execv("/sbin/open_mass_storage.sh", NULL);
        if (result)
            LOGE("open_mass_storage failed(%s)!\n", strerror(errno));
        _exit(-1);
    }
    waitpid(pid, &result, 0);
    if (WIFEXITED(result)) {
        if (WEXITSTATUS(result) != 0) {
            LOGE("open_mass_storage failed(%d)!\n", WEXITSTATUS(result));
            result = -1;
        }
        else
            result = 0;
    }
    else if (WIFSIGNALED(result)) {
        LOGE("open_mass_storage: open_mass_storage terminated on (%d)\n", WTERMSIG(result));
        result = -1;
    }
    else
        result = 0;
#endif

    sleep(2);
    usb_evt_socket = uevent_open_socket(USB_MSG_BUF_SIZE, true);
    if(usb_evt_socket < 0) {
        LOGE("uevent_open_socket failed!\n");
        return -1;
    }

    memset(usb_evt_msg, 0, USB_MSG_BUF_SIZE);
    set_usb_msg(USB_MSG_RET_READY, strlen(USB_MSG_RET_READY));
    while(1) {
        if((in = uevent_kernel_multicast_recv(usb_evt_socket, usb_evt_msg, USB_MSG_BUF_SIZE)) > 0) {
            if(strncmp(usb_evt_msg, USB_BURNING_UEVENT, strlen(USB_BURNING_UEVENT))) {
                LOGE("usb_evt_msg filter:%s\n", usb_evt_msg);
                memset(usb_evt_msg, 0, USB_MSG_BUF_SIZE);
                continue;
            }
            LOGE("usb_evt_msg:%s\n", usb_evt_msg);
            memset(usb_evt_msg, 0, USB_MSG_BUF_SIZE);
            sleep(1);
            in = get_usb_msg(usb_evt_msg);
            if(in > 0) {
                printf("usb_evt_msg=%s\n", usb_evt_msg);
                usb_cmd_process(usb_evt_msg, in);
            }
            memset(usb_evt_msg, 0, USB_MSG_BUF_SIZE);
        }
    }

    return 0;
}

void *usb_evt_manager(void *arg) {
    return NULL;
}

